import time, os, sys
import socket
import _thread
import gc
import utime
import network

from media.sensor import *
from media.display import *
from media.media import *
from CameraStreamer import CameraStreamer


def setup_ap_mode():
    print("[调试] 初始化AP模式...")
    ap = network.WLAN(network.AP_IF)
    ap.active(True)
    ap.config(ssid="K230-Camera", key="12345678")
    print("[调试] AP模式已启动，IP:", ap.ifconfig()[0])
    return ap


def http_server():
    """HTTP服务器线程"""
    try:
        # 创建套接字
    try:
        s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
        s.bind(('0.0.0.0', 80))
        s.listen(5)
            # 非阻塞模式，避免在accept里阻塞
            s.setblocking(False)
        print("[调试] HTTP服务器已启动，监听端口80")
        except Exception as e:
            print(f"[错误] HTTP服务器创建失败: {e}")
            return
        
        # 响应HTML内容
        html_response = """HTTP/1.1 200 OK
Content-Type: text/html; charset=utf-8

<!DOCTYPE html>
<html>
<head>
    <title>K230 Camera</title>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
</head>
<body>
    <h1>K230 Camera Web Server</h1>
    <p>请使用WebSocket客户端连接到 ws://192.168.169.1:6001 查看视频流</p>
    <p>或直接浏览器打开本页面</p>
</body>
</html>
"""
        
        # 主循环
        while True:
            try:
                # 非阻塞接受连接
                conn, addr = s.accept()
                print("[调试] 新HTTP客户端连接:", addr)
                
                try:
                    # 设置超时，避免在recv阻塞
                    conn.settimeout(2.0)
                    request = conn.recv(1024).decode('utf-8', 'ignore')
                    conn.send(html_response.encode('utf-8'))
                except Exception as e:
                    print(f"[警告] HTTP请求处理失败: {e}")
                finally:
                    # 确保连接关闭
                    try:
            conn.close()
                    except:
                        pass
                        
            except OSError as e:
                # 非阻塞模式下，没有连接请求会抛出异常
                if e.args[0] != 11:  # EAGAIN
                    print(f"[警告] HTTP accept失败: {e}")
                # 短暂休眠，避免CPU占用过高
                time.sleep_ms(100)
                
            except Exception as e:
                print(f"[警告] HTTP服务器循环异常: {e}")
                time.sleep_ms(100)
                
            # 允许其他任务执行
            time.sleep_ms(10)
            
    except Exception as e:
        print("[错误] HTTP服务器异常:", e)


def main_camera_stream():
    print("[调试] 启动主程序...")
    gc.collect()
    
    # 提前定义变量，避免 finally 报错
    streamer = None
    sensor = None
    ap = None

    try:
        free_mem = gc.mem_free()
        total_mem = gc.mem_alloc() + free_mem
        print(f"[调试] 可用内存: {free_mem} / 总: {total_mem}")

        if free_mem < 500000:
            print("[警告] 可用内存较低，尝试清理...")
            for _ in range(3):
                gc.collect()
                time.sleep_ms(100)
            free_mem = gc.mem_free()
            print(f"[调试] 清理后可用内存: {free_mem}")
    
        ap = setup_ap_mode()
        if not ap:
            print("[错误] 无法设置AP模式")
            return
        
        print("[调试] 启动HTTP服务器线程...")
        try:
            http_thread = _thread.start_new_thread(http_server, ())
            print("[调试] HTTP服务器线程已启动")
            # 等待一小段时间确保HTTP服务器线程启动
            time.sleep_ms(100)
        except Exception as e:
            print(f"[错误] 启动HTTP服务器线程失败: {e}")
            # 继续执行，HTTP服务器不是关键功能
        
        print("[调试] 配置媒体管理器...")
            config = k_vb_config()
        config.max_pool_cnt = 5  # 增加池数量
        
        # 设置第一个缓冲池，用于编码
        config.comm_pool[0].blk_size = 2 * 1024 * 1024  # 增加块大小到2MB
        config.comm_pool[0].blk_cnt = 12  # 显著增加块数量
            config.comm_pool[0].mode = VB_REMAP_MODE_NOCACHE
        
        # 设置第二个缓冲池，用于图像旋转
        config.comm_pool[1].blk_size = 1920 * 1080 * 3  # 足够大以容纳全尺寸图像
        config.comm_pool[1].blk_cnt = 8  # 增加块数量
        config.comm_pool[1].mode = VB_REMAP_MODE_NOCACHE
        
        # 设置第三个缓冲池，用于显示
        config.comm_pool[2].blk_size = 800 * 480 * 4  # 适合屏幕分辨率
        config.comm_pool[2].blk_cnt = 8  # 增加块数量
        config.comm_pool[2].mode = VB_REMAP_MODE_NOCACHE
        
        # 设置第四个缓冲池，专门用于传感器通道0
        config.comm_pool[3].blk_size = 320 * 240 * 3  # 适合传感器通道0分辨率
        config.comm_pool[3].blk_cnt = 8
        config.comm_pool[3].mode = VB_REMAP_MODE_NOCACHE
        
        # 设置第五个缓冲池，专门用于传感器通道2
        config.comm_pool[4].blk_size = 320 * 240 * 3  # 适合传感器通道2分辨率
        config.comm_pool[4].blk_cnt = 8
        config.comm_pool[4].mode = VB_REMAP_MODE_NOCACHE
        
            ret = MediaManager._config(config)
            if not ret:
                raise RuntimeError("缓冲区配置失败")
        
        # 初始化显示
        try:
            print("[调试] 初始化显示设备...")
            Display.init(Display.ST7701, width=800, height=480, osd_num=3, to_ide=True)
            print("[调试] 显示设备初始化成功")
        except Exception as e:
            print(f"[警告] 初始化显示失败，可能影响图像显示: {e}")
            
        print("[调试] 初始化传感器...")
            sensor = Sensor(id=2)
            sensor.reset()
            
        # 先等待一段时间让传感器稳定
        time.sleep_ms(500)
        
        # 设置通道0用于显示，使用更保守的分辨率
        print("[调试] 设置传感器通道0...")
        # 通道0使用较小分辨率，确保能够获取图像
        sensor.set_framesize(width=320, height=240, chn=CAM_CHN_ID_0)
            sensor.set_pixformat(Sensor.RGB565, chn=CAM_CHN_ID_0)
            
        # 设置通道2用于编码，使用更保守的分辨率
        print("[调试] 设置传感器通道2...")
        sensor.set_framesize(width=320, height=240, chn=CAM_CHN_ID_2)
            sensor.set_pixformat(Sensor.YUV420SP, chn=CAM_CHN_ID_2)
        
        # 设置其他传感器参数以提高稳定性
        try:
            print("[调试] 配置传感器高级参数...")
            # 如果支持以下参数，则设置它们以提高稳定性
            if hasattr(sensor, 'set_auto_gain'):
                sensor.set_auto_gain(True)
            if hasattr(sensor, 'set_auto_exposure'):
                sensor.set_auto_exposure(True)
            if hasattr(sensor, 'set_auto_whitebal'):
                sensor.set_auto_whitebal(True)
            if hasattr(sensor, 'set_hmirror'):
                sensor.set_hmirror(False)
            if hasattr(sensor, 'set_vflip'):
                sensor.set_vflip(False)
        except Exception as e:
            print(f"[警告] 设置传感器高级参数失败: {e}")
            # 继续执行，这些参数不是必需的

        print("[调试] 创建CameraStreamer...")
        streamer = CameraStreamer(
            ip="0.0.0.0",
            port=6001,
            w=320,
            h=240,  # 与传感器通道2的分辨率匹配
            sensor=sensor,
            mode="websocket",
            debug=True  # 启用调试输出以便排查问题
        )

        print("[调试] 初始化媒体管理器...")
            MediaManager.init()
            
        print("[调试] 启动传感器...")
        sensor.run()
            time.sleep(1)
            
        print("[调试] 启动CameraStreamer...")
        streamer.start()

        print("[调试] 进入主循环...")
        # 创建时钟用于计算FPS
        try:
            clock = utime.clock()
            print("[调试] 时钟创建成功")
        except Exception as e:
            print(f"[错误] 创建时钟失败: {e}")
            raise
            
        loop_count = 0
        last_fps_report = 0
        
        while True:
            try:
                # 仅每100次循环输出一次循环次数
                if loop_count % 100 == 0:
                    print(f"[调试] 循环次数: {loop_count}")
                loop_count += 1
                
                # 步骤1: tick处理，简化处理不输出调试信息
                try:
                    clock.tick()  # 直接调用，不打印调试信息
                except Exception as e:
                    print(f"[错误] 步骤1: tick异常: {e}")
                
                # 步骤2: streamer处理 - 可能的阻塞点
                try:
                    if streamer and hasattr(streamer, 'check'):
                        # 直接在后台线程中运行check，不等待完成
                        def background_check():
                            try:
                                streamer.check()
                            except Exception as e:
                                print(f"[错误] 步骤2: check异常: {e}")
                            
                        # 启动线程运行check
                        try:
                            _thread.start_new_thread(background_check, ())
                        except:
                            # 如果无法创建线程，直接调用
            streamer.check()
                except Exception as e:
                    if loop_count % 100 == 0:  # 仅偶尔打印错误
                        print(f"[错误] 步骤2: streamer处理异常: {e}")
                
                # 步骤3: 获取图像 - 关键步骤
                try:
                    if sensor:
                        # 直接获取图像，不再输出调试信息
                        try:
                            # 分别获取用于编码和显示的图像
                            try:
                                # 通道2用于编码 (YUV420SP格式)
                                h265_img = sensor.snapshot(chn=CAM_CHN_ID_2)
                                
                                # 通道0用于显示 (RGB565格式)
                                display_img = sensor.snapshot(chn=CAM_CHN_ID_0)
                                
                                print("[调试] 使用两个通道获取图像成功") if loop_count % 100 == 0 else None
                            except Exception as e:
                                print(f"[错误] 获取图像失败: {e}")
                                # 尝试只获取显示用的图像
                                try:
                                    display_img = sensor.snapshot(chn=CAM_CHN_ID_0)
                                except:
                                    display_img = None
                            
                            # 步骤4: 显示图像 - 尽可能快速地完成
                            if 'Display' in globals() and display_img is not None:
                                try:
                                    Display.show_image(display_img)
                                except Exception as e:
                                    if loop_count % 50 == 0:  # 减少错误日志频率
                                        print(f"[错误] 显示图像失败: {e}")
                                        
                                # 使用display_img进行后续绘制
                            
                            # 步骤5: 绘制信息 - 减少绘制量
                            try:
                                # 获取FPS
                                fps_value = clock.fps()
                                
                                # 每10帧才绘制一次文本信息
                                if loop_count % 10 == 0 and display_img is not None:
                                    # 绘制FPS
                                    display_img.draw_string_advanced(10, 10, 24, f"FPS: {fps_value:.1f}", color=(255, 0, 0))
                                    
                                    # 获取IP
                                    ip_text = "IP: 未知"
                                    if ap and hasattr(ap, 'ifconfig'):
                                        try:
                                            ip_address = ap.ifconfig()[0]
                                            ip_text = f"IP: {ip_address}"
                                        except:
                                            pass
                                    display_img.draw_string_advanced(10, 40, 24, ip_text, color=(255, 0, 0))
                                    
                                    # 获取客户端计数
                                    client_count = "?"
                                    if streamer and hasattr(streamer, "get_client_count"):
                                        try:
                                            client_count = streamer.get_client_count()
                                        except:
                                            pass
                                    display_img.draw_string_advanced(10, 70, 24, f"连接: {client_count}", color=(255, 0, 0))
                                    
                                    # 每100帧打印一次FPS信息
                                    if loop_count % 100 == 0:
                                        print(f"[信息] FPS: {fps_value:.1f}, 客户端: {client_count}")
                            except Exception as e:
                                if loop_count % 50 == 0:  # 减少错误日志频率
                                    print(f"[错误] 绘制文本失败: {e}")
                        except Exception as e:
                            print(f"[错误] 步骤3: 图像处理异常: {e}")
                            
                            # 尝试恢复传感器
                            if ("failed" in str(e) or "format" in str(e)) and loop_count % 20 == 0:
                                print("[恢复] 尝试重新初始化传感器...")
                                try:
                                    # 停止传感器
                                    sensor.stop()
                                    time.sleep_ms(300)
                                    
                                    # 重置传感器
                                    sensor.reset()
                                    time.sleep_ms(300)
                                    
                                    # 清理内存
                                    gc.collect()
                                    time.sleep_ms(100)
                                    
                                    # 重新配置通道0用于显示
                                    print("[恢复] 配置通道0...")
                                    sensor.set_framesize(width=320, height=240, chn=CAM_CHN_ID_0)
                                    sensor.set_pixformat(Sensor.RGB565, chn=CAM_CHN_ID_0)
                                    time.sleep_ms(100)
                                    
                                    # 重新配置通道2用于编码
                                    print("[恢复] 配置通道2...")
                                    sensor.set_framesize(width=320, height=240, chn=CAM_CHN_ID_2)
                                    sensor.set_pixformat(Sensor.YUV420SP, chn=CAM_CHN_ID_2)
                                    time.sleep_ms(100)
                                    
                                    # 重新启动传感器
                                    print("[恢复] 启动传感器...")
                                    sensor.run()
                                    time.sleep_ms(500)
                                    print("[恢复] 传感器重新初始化完成")
                                except Exception as e2:
                                    print(f"[错误] 传感器恢复失败: {e2}")
                    else:
                        print("[警告] 步骤3: 传感器对象无效")
                except Exception as e:
                    if loop_count % 50 == 0:  # 减少错误日志频率
                        print(f"[错误] 步骤3: 未处理的异常: {e}")
                
                # 步骤6: 系统维护
                try:
                    # 仅在需要时执行GC
                    if loop_count % 10 == 0:  # 每10次循环执行一次GC
                gc.collect()
            
                    # 只有在必要时调用exitpoint
                    if loop_count % 5 == 0:  # 每5次循环调用一次exitpoint
            os.exitpoint()
                except Exception as e:
                    print(f"[错误] 步骤6: 系统维护异常: {e}")
                
                # 输出统计信息
                if loop_count % 50 == 0:  # 每50次循环输出一次统计信息
                    try:
                        free_mem = gc.mem_free()
                        total_mem = gc.mem_alloc() + free_mem
                        print(f"[统计] 循环: {loop_count}, FPS: {fps_value:.1f}, 内存: {free_mem/1024:.1f}KB / {total_mem/1024:.1f}KB ({free_mem*100/total_mem:.1f}%)")
                    except:
                        pass
                
            except Exception as e:
                print(f"[错误] 循环顶层异常: {e}")
            
    except KeyboardInterrupt:
        print("[调试] 用户中断")
    except Exception as e:
        print("[错误] 主循环异常:", e)
    finally:
        print("[调试] 清理资源...")
        if streamer:
        try:
                streamer.deint()
                print("[调试] CameraStreamer已释放")
        except Exception as e:
            print("[错误] 清理streamer失败:", e)
        if sensor:
        try:
                sensor.stop()
                print("[调试] 传感器已停止")
        except Exception as e:
            print("[错误] 停止sensor失败:", e)
        try:
            MediaManager.deinit()
            print("[调试] 媒体管理器已释放")
        except Exception as e:
            print("[错误] 媒体管理器清理失败:", e)
        print("[调试] 程序结束")


if __name__ == "__main__":
    main_camera_stream()
